package guinew.view;


import guinew.controller.MainViewController;
import guinew.model.MainViewModel;

import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Image;
import java.awt.Insets;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.InputEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.util.Observable;
import java.util.Observer;


import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.ListCellRenderer;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.WindowConstants;
import javax.swing.border.BevelBorder;
import javax.swing.filechooser.FileFilter;
import javax.swing.tree.DefaultMutableTreeNode;


import panel.JGradientPanel;
import panel.JRoundedPanel;
import redsig.redaction.Redacter;

public class MainView extends AbstractView implements Observer{
	/**
	 * 
	 */
	private static final long serialVersionUID = -5082027192629326733L;
	private int width = 800;
	private int height = 780;
	private int splashHeight = 300;
	private int splashWidth = 400;
	private Timer t = null;
	private Dimension screenSize;
	private JFrame splashScreen;
	private JPanel splashPanel;
	private JPanel innerPanel;
	
	public static final String TITLE = "Redactable Signatures";
	//content panel
	private JPanel content;
	public final Color BASE_COLOR = new Color(230, 230, 255); 
	
	//Menubar
	private JMenuBar menuBar;
	private JMenu mainMenu;
	private JMenuItem open;
	private JMenuItem generate;
	
	//title panel
	private JPanel titlePanel;
	
	//Tree view
	private JPanel treePanel;
	private JScrollPane treeScrollPane;
	private JTree domTree;
	
	//redaction queue
	private JPanel redactionQueuePanel;
	private JScrollPane redactionQueueScrollPane;
	private JList redactionQueue;
	
	//messages
	private JPanel messagePanel;
	
	//private key
	private JPanel privateKeyPanel;
	private JLabel privateKeyLabel;
	
	//public key
	private JPanel publicKeyPanel;
	private JLabel publicKeyLabel;
	private JLabel verifiedLabel;
	
	//controls
	private JPanel controlPanel;
	private JButton redactButton;
	private JButton signButton;
	private JButton verifyButton;
	
	//tree popup menu
	private JPopupMenu treePopupMenu;
	private JMenuItem menuItemAddToQueue;
	private JMenuItem menuItemViewNodeData;
	
	//redaction list popup menu
	private JPopupMenu redactionQueuePopupMenu;
	private JMenuItem menuItemRemoveFromQueue;
	
	//controller
	private MainViewController controller;
	
	public MainView(MainViewController controller){
		super();
		//set controller
		this.controller = controller;
		this.controller.getModel().addObserver(this);
		this.setTitle(TITLE);
		this.setResizable(false);
		//Set Look & Feel
		try {
			javax.swing.UIManager.setLookAndFeel(javax.swing.UIManager.getSystemLookAndFeelClassName());
		} catch(Exception e) {
			e.printStackTrace();
		}
		screenSize = Toolkit.getDefaultToolkit().getScreenSize();
	    
		showSplashScreen();
		
		t = new Timer(2000, new ActionListener() {
	          public void actionPerformed(ActionEvent e) {
	      		initGUI();
	          }
	       });
		t.start();
	}
	
	private void showSplashScreen(){    
		splashScreen = new JFrame();
		splashScreen.setUndecorated(true);
		splashScreen.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
		splashScreen.setSize(splashWidth, splashHeight);
		splashScreen.setLocation(screenSize.width/2 - splashWidth/2, screenSize.height/2 - splashHeight/2);
		splashScreen.setVisible(true);
		splashScreen.setResizable(false);
		
		splashPanel = new JPanel();
		splashPanel.setBounds(0, 0, splashWidth, splashHeight);
		//splashPanel.setBackground(new Color(180, 207, 236));
		splashPanel.setBackground(Color.BLACK);
		splashPanel.setLayout(null);
		splashScreen.getContentPane().add(splashPanel, BorderLayout.CENTER);
		
		innerPanel = new JPanel();
		innerPanel.setBounds(1, 1, splashWidth-2, splashHeight-2);
		innerPanel.setBackground(BASE_COLOR);
		innerPanel.setLayout(new BorderLayout());
		splashPanel.add(innerPanel);
		
		JLabel authorLabel = new JLabel();
		authorLabel.setHorizontalAlignment(SwingConstants.RIGHT);
		authorLabel.setText("Bacher Florian & Vavti Matthias");
		innerPanel.add(authorLabel, BorderLayout.SOUTH);
	}
	
	/**
	 * Initializes the GUI and its Components
	 */
	private void initGUI() {
		t.stop();
		splashScreen.dispose();
		this.setBounds((screenSize.width/2-width/2), (screenSize.height/2-height/2), width, height);
		this.setSize(new Dimension(width, height));
		this.setDefaultCloseOperation(EXIT_ON_CLOSE);
		
		content = new JGradientPanel(BASE_COLOR);
		content.setLayout(new GridBagLayout());
		
		this.setLayout(new BorderLayout());
		this.add(content);
		this.setVisible(true);
		
		//init MenuBar
		initMenuBar();
		//init title panel
		//initTitlePanel();
		//init tree panel
		initTreePanel();
		//init redaction panel
		initRedactionQueuePanel();
		
		initMessagePanel();
		
		//init private key panel
//		initPrivateKeyPanel();
//		//init public key panel
//		initPublicKeyPanel();
		//init controls
		initControls();
		//init popup menu
		initPopupMenu();
	}
	
	/**
	 * GUI initialization
	 */
	
	public void initMenuBar(){
		menuBar = new JMenuBar();
		menuBar.setBackground(BASE_COLOR);
		menuBar.setOpaque(false);
		this.setJMenuBar(menuBar);
			
		mainMenu = new JMenu();
		mainMenu.setBackground(BASE_COLOR);
		mainMenu.setOpaque(false);
		mainMenu.setText("File");
		menuBar.add(mainMenu);
		
		open = new JMenuItem();
		open.setText("Open");
		open.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent evt) {
				controller.openXmlFileChooser();
			}
		});
		mainMenu.add(open);
		
		generate = new JMenuItem();
		generate.setText("Generate XML File");
		generate.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent evt) {
				new GenerationView();
			}
		});
		mainMenu.add(generate);
	}
	
	public void initTreePanel(){
		treePanel = new JGradientPanel(BASE_COLOR);
		treePanel.setBorder(BorderFactory.createLineBorder(Color.BLACK));
		treePanel.setVisible(true);
		addComponent(treePanel, 0, 1, 2, 6, 150, 600, GridBagConstraints.BOTH, new Insets(0, 0, 0, 5));
		treePanel.setLayout(new BorderLayout());
		treeScrollPane = new JScrollPane();
		treeScrollPane.setOpaque(false);
		treePanel.add(treeScrollPane, BorderLayout.CENTER);
		domTree = new JTree();
		domTree.setVisible(false);
		
		domTree.addMouseListener(new MouseAdapter(){
			public void mouseReleased(MouseEvent e) {
				//right mouse button released?
				if((e.getModifiers() & InputEvent.BUTTON3_MASK)== InputEvent.BUTTON3_MASK){
					int row = domTree.getRowForLocation(e.getX(), e.getY());
					if(domTree.getPathForLocation(e.getX(), e.getY()) != null){
						DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) domTree.getPathForLocation(e.getX(), e.getY()).getLastPathComponent();
						domTree.setSelectionRow(row);
						controller.setSelectedNode(selectedNode);
						if(e.isPopupTrigger()){
							if(controller.isNodeInRedactionQueue(selectedNode)){
								menuItemAddToQueue.setEnabled(false);
							}
						}
						treePopupMenu.show((JComponent)e.getSource(), e.getX(), e.getY());
					}
				}
            } 			
		});
		treeScrollPane.setViewportView(domTree);
		addTitlePanel(treePanel, "Document Tree");
	}

	public void initRedactionQueuePanel(){
		redactionQueuePanel = new JPanel();
		redactionQueuePanel.setBorder(BorderFactory.createLineBorder(Color.BLACK));
		redactionQueuePanel.setOpaque(false);
		redactionQueuePanel.setVisible(true);
		addComponent(redactionQueuePanel, 2, 1, 2, 4, 100, 400, GridBagConstraints.BOTH, new Insets(0, 5, 5, 0));
		redactionQueuePanel.setLayout(new BorderLayout());
		redactionQueueScrollPane = new JScrollPane();
		redactionQueueScrollPane.setOpaque(false);
		redactionQueuePanel.add(redactionQueueScrollPane, BorderLayout.CENTER);
		redactionQueue = new JList();
		redactionQueueScrollPane.setViewportView(redactionQueue);
		redactionQueue.setOpaque(false);
		addTitlePanel(redactionQueuePanel, "Redaction Queue");
		redactionQueue.addMouseListener(new MouseAdapter(){
			public void mousePressed(MouseEvent e) {
				if(SwingUtilities.isRightMouseButton(e)){
    				redactionQueue.setSelectedIndex(redactionQueue.locationToIndex(e.getPoint()));
    				if(redactionQueue.getSelectedValue()!=null)
    					redactionQueuePopupMenu.show((JComponent)e.getSource(), e.getX(), e.getY());
				}
			}
		});
	}
	
	public void initMessagePanel(){
		messagePanel = new JPanel();
		messagePanel.setBorder(BorderFactory.createLineBorder(Color.BLACK));
		messagePanel.setOpaque(false);
		messagePanel.setVisible(true);
		addComponent(messagePanel, 2, 5, 2, 2, 100, 30, GridBagConstraints.BOTH, new Insets(5, 5, 5, 0));
		messagePanel.setLayout(new BorderLayout());
		addTitlePanel(messagePanel, "Messages");
		
		//private key label brauch'ma derweil eigentlich nit so recht....
		
//		privateKeyLabel = new JLabel();
//		privateKeyLabel.setOpaque(false);
//		privateKeyLabel.setFont(new Font("Arial", Font.ITALIC, 14));
//		messagePanel.add(privateKeyLabel, BorderLayout.WEST);
		
		publicKeyLabel = new JLabel();
		publicKeyLabel.setOpaque(false);
		publicKeyLabel.setFont(new Font("Arial", Font.ITALIC, 14));
		messagePanel.add(publicKeyLabel, BorderLayout.CENTER);
		
		verifiedLabel = new JLabel();
		verifiedLabel.setFont(new Font("Arial", Font.BOLD, 14));
		messagePanel.add(verifiedLabel, BorderLayout.SOUTH);
	}
	
	public void initPrivateKeyPanel(){
		privateKeyPanel = new JPanel();
		privateKeyPanel.setBorder(BorderFactory.createLineBorder(Color.BLACK));
		privateKeyPanel.setOpaque(false);
		privateKeyPanel.setVisible(true);
		addComponent(privateKeyPanel, 2, 5, 2, 1, 100, 30, GridBagConstraints.BOTH, new Insets(5, 5, 5, 0));
		privateKeyPanel.setLayout(new BorderLayout());
		addTitlePanel(privateKeyPanel, "Private Key");
		privateKeyLabel = new JLabel();
		privateKeyLabel.setOpaque(false);
		privateKeyLabel.setFont(new Font("Arial", Font.ITALIC, 14));
		privateKeyPanel.add(privateKeyLabel, BorderLayout.CENTER);
	}
	
	public void initPublicKeyPanel(){
		publicKeyPanel = new JPanel();
		publicKeyPanel.setBorder(BorderFactory.createLineBorder(Color.BLACK));
		publicKeyPanel.setOpaque(false);
		publicKeyPanel.setVisible(true);
		addComponent(publicKeyPanel, 3, 6, 2, 1, 100, 70, GridBagConstraints.BOTH, new Insets(5, 5, 0, 0));
		publicKeyPanel.setLayout(new BorderLayout());
		addTitlePanel(publicKeyPanel, "Public Key");
		publicKeyLabel = new JLabel();
		publicKeyLabel.setOpaque(false);
		publicKeyLabel.setFont(new Font("Arial", Font.ITALIC, 14));
		publicKeyPanel.add(publicKeyLabel, BorderLayout.CENTER);
		verifiedLabel = new JLabel();
		verifiedLabel.setFont(new Font("Arial", Font.BOLD, 14));
		publicKeyPanel.add(verifiedLabel, BorderLayout.SOUTH);
	}
	
	public void initControls(){
		controlPanel = new JGradientPanel(BASE_COLOR.darker());
		//controlPanel.setOpaque(false);
		addComponent(controlPanel, 0, 7, 4, 1, 0, 50, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0));
		
		redactButton = new JButton("Redact");
		signButton = new JButton("Sign Document...");
		verifyButton = new JButton("Verify Document...");		
		
		controlPanel.add(redactButton);
		controlPanel.add(signButton);
		controlPanel.add(verifyButton);
		
		redactButton.addActionListener(new ActionListener(){

			@Override
			public void actionPerformed(ActionEvent arg0) {
				controller.redactButtonPressed();
			}
		});
		
		signButton.addActionListener(new ActionListener(){

			@Override
			public void actionPerformed(ActionEvent arg0) {
				controller.signButtonPressed();
			}
		});
		
		verifyButton.addActionListener(new ActionListener(){

			@Override
			public void actionPerformed(ActionEvent e) {
				controller.verifyButtonPressed();
			}	
		});
	}
	
	public void initPopupMenu(){
		treePopupMenu = new JPopupMenu();
		menuItemAddToQueue = new JMenuItem();
		menuItemAddToQueue.setText("Add to redaction queue");
		menuItemAddToQueue.addActionListener(new ActionListener(){
			@Override
			public void actionPerformed(ActionEvent arg0) {
				controller.addSelectedNodeToRedactionQueue();
			}
		});
		treePopupMenu.add(menuItemAddToQueue);
		menuItemViewNodeData = new JMenuItem();
		menuItemViewNodeData.setText("View node data");
		menuItemViewNodeData.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent arg0) {				
    			DetailView dv = new DetailView(controller.getSelectedNode());
    			dv.run();
			}			
		});
		treePopupMenu.add(menuItemViewNodeData);
		
		redactionQueuePopupMenu = new JPopupMenu();
		menuItemRemoveFromQueue = new JMenuItem();
		menuItemRemoveFromQueue.setText("Remove from redaction queue");
		menuItemRemoveFromQueue.addActionListener(new ActionListener(){
			@Override
			public void actionPerformed(ActionEvent arg0) {
				DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) redactionQueue.getSelectedValue();
				controller.removeFromRedactionQueue(selectedNode);
			}
		});
		redactionQueuePopupMenu.add(menuItemRemoveFromQueue);
		redactionQueuePopupMenu.add(menuItemViewNodeData);
	}
	
	
	public void addComponent(JComponent component, int gridx, int gridy, 
								int gridwidth, int gridheight, 
								int ipadx, int ipady, int fill,
								Insets insets){
		GridBagConstraints c = new GridBagConstraints();
		//set position
		c.gridx = gridx;
		c.gridy = gridy;
		
		//set weight
		c.weightx = 0.5;
		c.weighty = 0.5;
		
		//set grid size
		c.gridwidth = gridwidth;
		c.gridheight = gridheight;
		
		//set padding
		c.ipadx = ipadx;
		c.ipady = ipady;
		
		//set fill options
		c.fill = fill;
		
		//set anchor
		c.anchor = GridBagConstraints.PAGE_START;
		
		//set external padding
		c.insets = insets;
		
		content.add(component, c);
	}
	
	public void addTitlePanel(JPanel component, String title){
		JPanel titlePanel = new JGradientPanel(BASE_COLOR.darker());
		component.add(titlePanel, BorderLayout.NORTH);
		JLabel titleLabel = new JLabel(title);
		titleLabel.setFont(new Font("Arial", Font.BOLD, 14));
		titleLabel.setVisible(true);
		titleLabel.setOpaque(false);
		titlePanel.add(titleLabel, BorderLayout.CENTER);
	}

	@Override
	public void update(Observable arg0, Object arg1) {	
		if(arg0.getClass() == MainViewModel.class){
			MainViewModel model = (MainViewModel)arg0;
			//set window title
			this.setTitle(getTitle() + " - " + model.getXmlFileName());
			//set dom tree model
			domTree.setModel(model.getTreeModel());
			domTree.setVisible(true);
			//set redaction queue list model
			redactionQueue.setModel(model.getRedactionQueueModel());
			//set private key file name
			//privateKeyLabel.setText("Private Key File: " + model.getPrivateKeyFileName());
			//set public key file name
			publicKeyLabel.setText("Certificate File: " + model.getPublicKeyFileName());
			//set verified label
			if(model.isVerified()){
				verifiedLabel.setText("Document verified");
				verifiedLabel.setForeground(Color.GREEN);
			}else{
				verifiedLabel.setText("Document not verified");
				verifiedLabel.setForeground(Color.RED);
			}
			
		}
	}
}
